package com.bluexmicro.utils.recyclerview

import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bluexmicro.utils.dpToPx
import kotlin.math.abs
import kotlin.math.min

class StickyHeaderDecoration(
    context: Context,
    private val callback: Callback,
    stickyBgColor: Int = 0xFF2E2E2E.toInt(),
    titleColor: Int = 0xff777777.toInt(),
    subTitleColor: Int = 0xFF717171.toInt()
) : RecyclerView.ItemDecoration() {

    private var titleHeight: Int = 30
    private var subTitleHeight: Int = 15
    private var mPadding = 8f.dpToPx(context)

    private val mPaint = Paint().apply {
        color = stickyBgColor
        style = Paint.Style.FILL
        isAntiAlias = true
    }
    private val titlePaint = TextPaint().apply {
        color = titleColor
        textSize = 24f.sp2px(context)
        typeface = Typeface.DEFAULT_BOLD
        isAntiAlias = true
        textAlign = Paint.Align.LEFT
        titleHeight =
            abs(this.fontMetrics.ascent + this.fontMetrics.leading + this.fontMetrics.descent).toInt()
    }

    private val subTitlePaint = TextPaint().apply {
        color = subTitleColor
        textSize = 10f.sp2px(context)
        isAntiAlias = true
        textAlign = Paint.Align.LEFT
        subTitleHeight =
            abs(this.fontMetrics.ascent + this.fontMetrics.leading + this.fontMetrics.descent).toInt()
    }


    private fun Float.sp2px(context: Context): Float {
        val scale = context.resources.displayMetrics.scaledDensity
        return (this * scale + 0.5f).toFloat()
    }

    private fun getHeadHeight(): Int {
        return (titleHeight + subTitleHeight + mPadding * 2.5).toInt()
    }

    // 给组内第一个Item增加额外空间来绘制Header
    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        val pos = parent.getChildAdapterPosition(view)
        if (isFirstInGroup(pos)) {
            outRect.top = getHeadHeight()
        }
    }

    // 绘制Header
    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDraw(c, parent, state)

        val left = 0f
        val right = parent.width.toFloat()
        val childCount = parent.childCount

        for (i in 0 until childCount) {
            val child = parent.getChildAt(i)
            val pos = parent.getChildAdapterPosition(child)
            if (pos == RecyclerView.NO_POSITION || !isFirstInGroup(pos)) continue
            val top = child.top - getHeadHeight().toFloat()
            val bottom = top + getHeadHeight().toFloat()
            val title = callback.getGroupTitle(pos)
            val sub = callback.getGroupSubTitle(pos)
            c.drawTitle(RectF(left, top, right, bottom), title, sub)
        }
    }

    // 绘制StickyHeader
    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(c, parent, state)
        val manager = parent.layoutManager as LinearLayoutManager
        // 找到RecyclerView第一个可见的itemView在adapter中的位置
        val firstPos = manager.findFirstVisibleItemPosition()
        if (firstPos == RecyclerView.NO_POSITION)
            return

        val rectF = if (isLastInGroup(firstPos)) {
            // 标题要跟着组内最后一个滑走
            val child = parent.findViewHolderForAdapterPosition(firstPos)?.itemView ?: return
            val bottom = min(child.bottom, getHeadHeight()).toFloat()
            val top = bottom - getHeadHeight().toFloat()
            val left = 0f
            val right = parent.width.toFloat()
            RectF(left, top, right, bottom)
        } else {
            // 直接绘制在顶部
            val top = 0f
            val bottom = getHeadHeight().toFloat()
            val left = 0f
            val right = parent.width.toFloat()
            RectF(left, top, right, bottom)
        }

        val title = callback.getGroupTitle(firstPos)
        val sub = callback.getGroupSubTitle(firstPos)
        c.drawTitle(rectF, title, sub)
    }

    private fun Canvas.drawTitle(rectF: RectF, title: String, sub: String) {
        mPaint.color = Color.WHITE
        drawRect(rectF, mPaint)
        mPaint.color = 0xFFDAD8CA.toInt()
        drawRoundRect(
            rectF.left + mPadding * 2,
            rectF.bottom - mPadding * 1.5f - subTitleHeight - titleHeight / 2,
            titlePaint.measureText(title) + rectF.left + mPadding * 2,
            rectF.bottom - mPadding * 1.5f - subTitleHeight,
            mPadding.toFloat(), mPadding.toFloat(),
            mPaint
        )
        drawText(
            title,
            rectF.left + mPadding * 2,
            rectF.bottom - mPadding * 1.5f - subTitleHeight,
            titlePaint
        )
        drawText(
            sub,
            rectF.left + mPadding * 2,
            rectF.bottom - mPadding,
            subTitlePaint
        )
    }

    // 判断item是否所在组的内最后一个item
    private fun isLastInGroup(pos: Int): Boolean {
        if (pos < 0)
            return false
        val index = callback.getGroupIndex(pos)
        val preIndex = callback.getGroupIndex(pos + 1)
        return index != preIndex
    }

    // 判断item是否所在组的内第一个item
    private fun isFirstInGroup(pos: Int): Boolean {
        if (pos < 0)
            return false
        val index = callback.getGroupIndex(pos)
        val preIndex = callback.getGroupIndex(pos - 1)
        return index != preIndex
    }

    // 回调获取item所在组的下标和标题
    interface Callback {
        fun getGroupIndex(pos: Int): Int
        fun getGroupTitle(pos: Int): String
        fun getGroupSubTitle(pos: Int): String
    }
}

